//
//  ZZAudioManager.m
//  RecorderTest
//
//  Created by 张彦东 on 2017/5/18.
//  Copyright © 2017年 Z. All rights reserved.
//

#import "ZZAudioManager.h"
#import <AVFoundation/AVFoundation.h>
#import "ZZAudioModel.h"
#import "ZZAudioParameter.h"

#define kAudioArrayFileName @"audioArray"

@interface ZZAudioManager () <AVAudioRecorderDelegate, AVAudioPlayerDelegate>

@end

@implementation ZZAudioManager
{
    AVAudioRecorder *_recorder;
    AVAudioPlayer*_audioPlayer;
    AVAudioSession *_audioSession;
    
    NSTimer *_timer;
    ZZAudioModel *_currentRecordAudioModel;
    ZZAudioModel *_currentPlayAudioModel;
    NSTimeInterval _recordDuration; // 录音持续时间
}

@synthesize audioArray = _audioArray;

+ (instancetype)manager {
    static ZZAudioManager *manager;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [[self alloc] init];
        [manager setup];
    });
    return manager;
}

- (void)setup {
    _channelsIndex = 0;
    _sampleRateIndex = 0;
    _linearPCMBitDepthIndex = 0;
    _audioQualityIndex = 0;
    _encoderBitRateIndex = 0;
}

- (void)prepareAudio {
    if (!_audioSession) {
        _audioSession = [AVAudioSession sharedInstance];
        [_audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
    }
    [_audioSession setActive:YES error:nil];
}

- (void)quitAudio {
    [_audioSession setActive:NO error:nil];
}


// 录音初始化设置
- (void)configRecorder {
    if (_recorder) return;
    
    // 权限
    AVAudioSessionRecordPermission permission = [[AVAudioSession sharedInstance] recordPermission];
    if (permission != AVAudioSessionRecordPermissionGranted) {
        NSLog(@"需要获取权限");
        
        [AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio completionHandler:^(BOOL granted) {
            if (granted) {
                [self recordResum];
            } else {
                NSLog(@"获取权限失败");
            }
        }];
        return;
    }
    
    _currentRecordAudioModel = [[ZZAudioModel alloc] init];
    _currentRecordAudioModel.audioId = @(_audioArray.count + 1);
    _currentRecordAudioModel.name = [self newRecorderName];
    NSURL *fileUrl = [NSURL fileURLWithPath:[self filePathWithName:_currentRecordAudioModel.name]];
    _currentRecordAudioModel.url = fileUrl;
    NSDictionary *setting = [self recordSetting];
    NSError *error = nil;
    _recorder = [[AVAudioRecorder alloc] initWithURL:fileUrl settings:setting error:&error];
    if (error) {
        NSLog(@"--录音文件创建失败 %@", error);
        return;
    } else {
        NSLog(@"--录音文件创建成功");
    }
    _recorder.delegate = self;
    _recorder.meteringEnabled = YES;
    _recordDuration = 0;
    [_recorder prepareToRecord];
}
- (NSString *)newRecorderName {
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    formatter.dateFormat = @"yyyyMMddhhmmss";
    return [[formatter stringFromDate:[NSDate date]] stringByAppendingPathExtension:@"caf"];
}
- (NSString *)filePathWithName:(NSString *)fileName {
    NSString *urlStr = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    return [urlStr stringByAppendingPathComponent:fileName];
}
- (NSDictionary *)recordSetting {
    NSMutableDictionary *recSetting = [[NSMutableDictionary alloc] init];
    // General Audio Format Settings
    recSetting[AVFormatIDKey] = @(kAudioFormatLinearPCM);
    recSetting[AVSampleRateKey] = [ZZAudioParameter sampleRateParameterAtIndex:_sampleRateIndex];
    recSetting[AVNumberOfChannelsKey] = [ZZAudioParameter channelsParameterAtIndex:_channelsIndex];
    // Linear PCM Format Settings
    recSetting[AVLinearPCMBitDepthKey] = [ZZAudioParameter linearPCMBitDepthParameterAtIndex:_linearPCMBitDepthIndex];
    recSetting[AVLinearPCMIsBigEndianKey] = @YES;
    recSetting[AVLinearPCMIsFloatKey] = @YES;
//    recSetting[AVLinearPCMIsNonInterleavedKey] = @YES;
    // Encoder Settings
    recSetting[AVEncoderAudioQualityKey] = [ZZAudioParameter audioQualityParameterAtIndex:_audioQualityIndex];
    recSetting[AVEncoderBitRateKey] = [ZZAudioParameter encoderBitRateParameterAtIndex:_encoderBitRateIndex];
    
    NSLog(@"setting %@", recSetting);
    return [recSetting copy];
}

#pragma mark - public
- (void)recordResum {
    [self configRecorder];
    [_recorder record];
    [self startTimer];
}
- (void)recordPause {
    [self stopTimer];
    [_recorder pause];
}
- (void)recordStop {
    [self stopTimer];
    _recordDuration = _recorder.currentTime;
    [_recorder stop];
}

- (void)audioPlayWithAudioId:(NSNumber *)audioId {
    if (_currentPlayAudioModel) return;
    for (ZZAudioModel *model in _audioArray) {
        if (model.audioId.integerValue == audioId.integerValue) {
            _currentPlayAudioModel = model;
            break;
        }
    }
    if (_currentPlayAudioModel) {
        NSError *error = nil;
        _audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:_currentPlayAudioModel.url error:&error];
        _audioPlayer.numberOfLoops = 0;
        _audioPlayer.delegate = self;
        [_audioPlayer prepareToPlay];
        if (error) {
            NSLog(@"音频准备出错 : %@", error);
            NSLog(@"音频文件:%@", _currentPlayAudioModel.url.absoluteString);
        }
        [_audioPlayer play];
    } else {
        NSLog(@"音频文件不存在");
    }
}

- (void)audioStopWithAudioId:(NSNumber *)audioId {
    if (!_currentPlayAudioModel || _currentPlayAudioModel.audioId.integerValue != audioId.integerValue) return;
    // 停止播放
    [_audioPlayer stop];
}

#pragma mark - 私有方法
- (void)saveFile {
    [NSKeyedArchiver archiveRootObject:_audioArray toFile:[self filePathWithName:kAudioArrayFileName]];
}
- (NSArray *)getFile {
    return [NSKeyedUnarchiver unarchiveObjectWithFile:[self filePathWithName:kAudioArrayFileName]];
}

#pragma mark - audio 数组获取
- (NSArray *)audioArray {
    if (!_audioArray) {
        _audioArray = [self getFile];
    }
    return _audioArray;
}

#pragma mark - 循环计时器 获取录音相关数据
- (void)startTimer {
    if (!_timer) {
        _timer = [NSTimer scheduledTimerWithTimeInterval:0.1f target:self selector:@selector(handleRecorderData) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
    }
}
- (void)stopTimer {
    if (_timer) {
        [_timer invalidate];
        _timer = nil;
    }
}

// 计时循环处理录音数据
- (void)handleRecorderData {
    _recordDuration = _recorder.currentTime;
    [_recorder updateMeters];
    float peak0 = ([_recorder peakPowerForChannel:0] + 160.0) * (1.0 / 160.0);
    float peak1 = ([_recorder peakPowerForChannel:1] + 160.0) * (1.0 / 160.0);
    float ave0 = ([_recorder averagePowerForChannel:0] + 160.0) * (1.0 / 160.0);
    float ave1 = ([_recorder averagePowerForChannel:1] + 160.0) * (1.0 / 160.0);
    [[NSNotificationCenter defaultCenter] postNotificationName:ZZRecordMetersChangeNotification object:@[@(peak0), @(peak1), @(ave0), @(ave1), @(_recordDuration)]];
}

#pragma mark - AVAudioRecorderDelegate
- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag {
    NSLog(@"录音完成 - %@, successfullyFlag : %d", NSStringFromSelector(_cmd), flag);
    [[NSNotificationCenter defaultCenter] postNotificationName:ZZRecordStopNotification object:nil];
    if (flag) {
        _currentRecordAudioModel.duration = @(_recordDuration);
        
        NSError *fileError;
        // 这里用path 不能用absoluteString
        NSDictionary *fileAttr = [[NSFileManager defaultManager] attributesOfItemAtPath:recorder.url.path error:&fileError];
        if (fileError) {
            NSLog(@"录音文件读取错误 %@", fileError);
        } else {
            _currentRecordAudioModel.fileSize = fileAttr[NSFileSize];
        }
        NSLog(@"%@", _currentRecordAudioModel);
        NSMutableArray *newArray = [[NSMutableArray alloc] initWithArray:_audioArray];
        [newArray addObject:_currentRecordAudioModel];
        _audioArray = newArray;
        [self saveFile];
    } else {
        NSLog(@"未正常结束");
        if ([_recorder deleteRecording]) {
            NSLog(@"录音文件删除成功");
        } else {
            NSLog(@"录音文件删除失败");
        }
    }
    _currentRecordAudioModel = nil;
    _recorder = nil;
}

#pragma mark - AVAudioPlayerDelegate
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
    NSLog(@"音频播放完成 - %@, successfullyFlag : %d", NSStringFromSelector(_cmd), flag);
    if (flag) {
        [[NSNotificationCenter defaultCenter] postNotificationName:ZZAudioStopNotification object:_currentPlayAudioModel.audioId];
    }
    _audioPlayer = nil;
    _currentPlayAudioModel = nil;
}

@end

NSNotificationName const ZZAudioPlayNotification = @"ZZAudioPlayNotification";
NSNotificationName const ZZAudioStopNotification = @"ZZAudioStopNotification";

NSNotificationName const ZZRecordStopNotification = @"ZZRecordStopNotification";
NSNotificationName const ZZRecordMetersChangeNotification = @"ZZRecordMetersChangeNotification";
